//
// GPSMapEdit
// (c) Konstantin Galichsky (kg@geopainting.com), 2002-2004
//
// Copy the element of object to another zoom level.
//

# include "StdAfx.h"
# include "CopyElement.h"
# include "RefreshHoles.h"
# include "UndoRedo.h"
# include "Map.h"
# include "Types.h"
# include "Label.h"
# include "Globals.h"

class CCopyElementAction : public CEditAction {
  public:
	CCopyElementAction (size_t _cNewLevel, rgn_t * _pRgn, size_t _cElementOrOrigin) :
		m_cNewLevel (_cNewLevel),
		m_pRgn (_pRgn),
		m_cElementOrOrigin (_cElementOrOrigin),
		m_bWasModified ((_pRgn->dwFlags & rgn_t::fModified) != 0)
	{}

	virtual void GetName (string_t & _str) const;
	virtual cu_t CanUndo () const {return cuYes;}
	virtual bool Do ();
	virtual void Undo ();
	virtual void Redo ();

  private:
	const size_t m_cNewLevel;

	rgn_t * const m_pRgn;
	bool    const m_bWasModified;
	size_t  const m_cElementOrOrigin;
	size_t        m_cElementOrOriginNew;
};

void CCopyElementAction::GetName (string_t & _str) const {
	CCritSec::CLock lock (g_cs);

	assert (m_pRgn);
	_str.append ("copy element of [");
	GetHintText (* m_pRgn, _str);
	_str.append ("]");
}

bool CCopyElementAction::Do () {
	CCritSec::CLock lock (g_cs);

	assert (m_pRgn);

	if (m_pRgn->IsPolygon () || m_pRgn->IsPolyline ()) {
		m_cElementOrOriginNew = m_pRgn->elements.size ();

		// Create the element of the rgn.
		m_pRgn->elements.push_back (rgn_element_t ());
		rgn_element_t & element = m_pRgn->elements.back ();

		// Initialize the element of rgn.
		element.cFileOffset = -1;
		assert (m_cNewLevel < g_map.Levels.size () - 1);
		element.cLevel = m_cNewLevel;

		// Copy points.
		assert (m_cElementOrOrigin < m_pRgn->elements.size ());
		const points_t & points = m_pRgn->elements [m_cElementOrOrigin].points;
		element.points = points;
		// Round all points.
		g_map.pTypeSet->pfRoundPoints (g_map, m_cNewLevel, element.points);
		element.RemoveRepeatingPoints ();
	} else {
		assert (m_pRgn->IsPoint ());

		m_cElementOrOriginNew = m_pRgn->origins.size ();

		// Create the origin of the rgn.
		m_pRgn->origins.push_back (rgn_origin_t ());
		rgn_origin_t & origin = m_pRgn->origins.back ();

		// Initialize the origin of rgn.
		// NOTE: no need to copy the 'bHole' attribute because it will be updated later.
		origin.cFileOffset = -1;
		assert (m_cNewLevel < g_map.Levels.size () - 1);
		origin.cLevel = m_cNewLevel;

		// Copy point.
		assert (m_cElementOrOrigin < m_pRgn->origins.size ());
		origin.point = m_pRgn->origins [m_cElementOrOrigin].point;
		// Round point.
		g_map.pTypeSet->pfRoundPoint (g_map, m_cNewLevel, origin.point);
	}

	m_pRgn->RefreshAttributes (g_map);

	m_pRgn->dwFlags |= rgn_t::fModified;
	
	return true;
}

void CCopyElementAction::Undo () {
	CCritSec::CLock lock (g_cs);

	assert (m_pRgn);
	if (m_pRgn->origins.empty ()) {
		assert (m_cElementOrOrigin < m_pRgn->elements.size ());
		m_pRgn->elements [m_cElementOrOriginNew].bDeleted = true;
	} else {
		assert (m_cElementOrOrigin < m_pRgn->origins.size ());
		m_pRgn->origins [m_cElementOrOriginNew].bDeleted = true;
	}

	m_pRgn->RefreshAttributes (g_map);

	if (! m_bWasModified)
		m_pRgn->dwFlags &= ~rgn_t::fModified;
}

void CCopyElementAction::Redo () {
	CCritSec::CLock lock (g_cs);

	assert (m_pRgn);
	if (m_pRgn->origins.empty ()) {
		assert (m_cElementOrOrigin < m_pRgn->elements.size ());
		m_pRgn->elements [m_cElementOrOriginNew].bDeleted = false;
	} else {
		assert (m_cElementOrOrigin < m_pRgn->origins.size ());
		m_pRgn->origins [m_cElementOrOriginNew].bDeleted = false;
	}

	m_pRgn->RefreshAttributes (g_map);

	m_pRgn->dwFlags |= rgn_t::fModified;
}

////////////////////////////////////////////////

void CopyElement (size_t _cNewLevel, rgn_t * _pRgn, size_t _cElementOrOrigin) {
	assert (_cNewLevel < g_map.Levels.size () - 1);
	PerformEditAction (new CCopyElementAction (_cNewLevel, _pRgn, _cElementOrOrigin));

	if (_pRgn->IsPolygon ())
		RefreshHoles (_pRgn, true);
}
